package com.example.demo.service.impl;

import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.http.HttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.nio.entity.NStringEntity;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.example.demo.Util.ConnectionUtils;
import com.example.demo.config.Constant;
import com.example.demo.entity.Bayonet;
import com.example.demo.entity.CarInfo;
import com.example.demo.entity.Point;
import com.example.demo.mapper.HbaseCarsMessageMapper;
import com.example.demo.service.HbaseCarsMessageService;

import lombok.AllArgsConstructor;

@Service
@AllArgsConstructor
public class HbaseCarsMessageServiceImpl implements HbaseCarsMessageService {

    private static final Logger log = LoggerFactory.getLogger(HbaseCarsMessageServiceImpl.class);

    private static Connection connection;
    private static RestClient connector;


    @Autowired
    private final HbaseCarsMessageMapper hbaseCarsMessageMapper;

    @Override
    public List<Bayonet> getCarPassedBayonetInformation(String licenseNumber, String startTime, String endTime, String type) {
        List<JSONObject> jsonObjects = null;
//        HashMap<String, Object> map = new HashMap<>();
        List<Bayonet> bayonetList = new ArrayList<Bayonet>();
        try {
            jsonObjects = this.getESAppointInfo(licenseNumber, startTime, endTime, Constant.size);
            for (JSONObject jsonObject : jsonObjects) {
                //loc_id+capture_time
//                String locId = jsonObject.getString("loc_id");
//                String captureTime = jsonObject.getString("capture_time");
//                Result result = getTableName(Constant.HBASE_TBNAME, locId+"_"+captureTime, startTime, endTime);
//                assert result != null;
//                List<Cell> cells = result.listCells();
//                if(cells == null) continue;
//                for (Cell cell : cells) {
//                    map.put(Bytes.toString(CellUtil.cloneQualifier(cell)), Bytes.toString(CellUtil.cloneValue(cell)));
//                }
                String locationId = (String) jsonObject.get("location_id");
                String date = (String) jsonObject.get("capture_time");
                Bayonet bayonet = this.hbaseCarsMessageMapper.get(locationId);
                if(type!=null && !"".equals(type)) { //有传车辆类型过来
                	if (type.equals((String)jsonObject.get("brand_id"))) { //判断是不是该类型车辆
                		if (bayonet != null) {
    	                    //获取image_url
    	                    String imageUrl = (String) jsonObject.get("image_url1");
    	                    bayonet.setImageUrl(imageUrl);
    	                    bayonet.setLicenseNumber(licenseNumber);
    	                    bayonet.setDate(date);
    	                    bayonet.setType((String)jsonObject.get("brand_id"));
    	                    bayonetList.add(bayonet);
    	                }
                	}
	                
                }else { //无
                	 if (bayonet != null) {
 	                    //获取image_url
 	                    String imageUrl = (String) jsonObject.get("image_url1");
 	                    bayonet.setImageUrl(imageUrl);
 	                    bayonet.setLicenseNumber(licenseNumber);
 	                    bayonet.setDate(date);
 	                    bayonet.setType((String)jsonObject.get("brand_id"));
 	                    bayonetList.add(bayonet);
 	                }
                }
            }
        } catch (Exception e) {
            log.info("请检查输入参数! {}{}{}" + "licenseNumber= " + licenseNumber + "startTime= " + startTime + "endTime= " + endTime);
            e.printStackTrace();
        }
        return bayonetList;
    }

    @Override
    public List<Bayonet> getAllBayonetInformation() {
       return this.hbaseCarsMessageMapper.getBayonet();
//        return dataList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(()
//                -> new TreeSet<>(Comparator.comparing(data -> data.getId() + ";" + data.getPointname()))), ArrayList::new));
    }

    @Override
    public List<Bayonet> getPointCoordinateBayonetInformation(List<Point> points) {
        ArrayList<Bayonet> correctList = new ArrayList<>();
        try {
            List<Bayonet> bayonets = this.hbaseCarsMessageMapper.getBayonet();
            double polygonPointX = 0.0, polygonPointY = 0.0;
            Point2D.Double xyList = null;
            ArrayList<Point2D.Double> pointList = new ArrayList<>();
            for (Bayonet datum : bayonets) {
                double longitude = datum.getLongitude().doubleValue();
                double latitude = datum.getLatitude().doubleValue();
                xyList = new Point2D.Double(longitude, latitude);
                for (Point point : points) {
                    polygonPointX = Double.parseDouble(point.getX());
                    polygonPointY = Double.parseDouble(point.getY());
                    Point2D.Double xy = new Point2D.Double(polygonPointX, polygonPointY);
                    pointList.add(xy);
                }
                if (check(xyList, pointList)) {
                    correctList.add(datum);
                }
            }
        } catch (Exception e) {
            log.info("请检查输入参数! {}" + "points= " + points.toString());
            e.printStackTrace();
        }
        return correctList;
    }

    @Override
    public List<Bayonet> getNationalAndHighWayinateBayonetInformation() {
        List<Bayonet> resultList = new ArrayList<Bayonet>();
        List<Bayonet> dataList = this.hbaseCarsMessageMapper.getBayonet();
        for (Bayonet bayonet : dataList) {
            //if (bayonet.getPointname().contains("国道") || bayonet.getPointname().contains("高速")) {
            if ((bayonet.getPointname().contains("出口") || bayonet.getPointname().contains("入口")) && (bayonet.getPointname().contains("高速") || bayonet.getPointname().contains("国道"))) {
                resultList.add(bayonet);
            }
        }
        return resultList;
    }

    @Override
    public List<CarInfo> getTypeBayonetsInformation(String startTime, String endTime, String type, List<Bayonet> list) {
        List<JSONObject> jsonObjects = null;
//        HashMap<String, Object> map = new HashMap<>();
        List<CarInfo> cars = new ArrayList<CarInfo>();
//        Result result;
        try {
        	//遍历卡口信息
        	for (Bayonet bayonet : list) { //遍历卡口信息 获取所有卡口结构化数据
        		jsonObjects = this.getESLocationId(bayonet.getId(),startTime,endTime, Constant.lease_szie);
        		Bayonet bay = this.hbaseCarsMessageMapper.get(bayonet.getId().toString());
        		Long id = 0l;
        		String name = "";
        		if (bay !=null) {
        			id = bay.getId();
        			name = bay.getPointname();
        		}
        		 for (JSONObject jsonObject : jsonObjects) {
//                     String locId = jsonObject.getString("loc_id");
//                     String captureTime = jsonObject.getString("capture_time");
//                     result = getTableName(Constant.HBASE_TBNAME, locId + "_" + captureTime, startTime, endTime);
//                     assert result != null;
//                     List<Cell> cells = result.listCells();
//                     if (cells == null) continue;
//                     for (Cell cell : cells) {
//                    	 map.put(Bytes.toString(CellUtil.cloneQualifier(cell)), Bytes.toString(CellUtil.cloneValue(cell)));
//                     }
                     CarInfo info = new CarInfo();
                     // 根据车辆类型筛选
                     //type.equals(map.get("key"))
                     if (null == type||"".equals(type)) {
                         refine(cars, info, type, jsonObject, id, name);

                     } else if (jsonObject.get("brand_id").equals(type)) {
                         refine(cars, info, type, jsonObject, id, name);
                     }
                 }
			}
        } catch (Exception e) {
        	log.info("请检查输入参数!{}{}{}{}"+ "startTime= "+ startTime + "endTime= "+endTime + "type= "+type + "list= "+ list.toString());
            e.printStackTrace();
        }
        return cars; 
    }
    
    @Override
    public List<CarInfo> getLeaseBayonetsInformation(String startTime, String endTime, String type, List<Bayonet> list) {
        List<JSONObject> jsonObjects = null;
//        HashMap<String, Object> map = new HashMap<>();
        List<CarInfo> cars = new ArrayList<CarInfo>();
//        Result result;
        try {
        	//遍历卡口信息
        	for (Bayonet bayonet : list) { //遍历卡口信息 获取所有卡口结构化数据
        		jsonObjects = this.getESLocationId(bayonet.getId(),startTime,endTime,Constant.size); 
        		Bayonet bay = this.hbaseCarsMessageMapper.get(bayonet.getId().toString());
        		Long id = 0l;
        		String name = "";
        		if (bay !=null) {
        			id = bay.getId();
        			name = bay.getPointname();
        		}
        		 for (JSONObject jsonObject : jsonObjects) {
//                     String locId = jsonObject.getString("loc_id");
//                     String captureTime = jsonObject.getString("capture_time");
//                     result = getTableName(Constant.HBASE_TBNAME, locId + "_" + captureTime, startTime, endTime);
//                     assert result != null;
//                     List<Cell> cells = result.listCells();
//                     if (cells == null) continue;
//                     for (Cell cell : cells) {
//                    	 map.put(Bytes.toString(CellUtil.cloneQualifier(cell)), Bytes.toString(CellUtil.cloneValue(cell)));
//                     }
                     CarInfo info = new CarInfo();
                     // 根据车辆类型筛选
                     //type.equals(map.get("key"))
                     if (null == type||"".equals(type)) {
                         refine(cars, info, type, jsonObject,id, name);

                     } else if (jsonObject.get("brand_id").equals(type)) {
                         refine(cars, info, type, jsonObject,id, name);
                     }
                 }
			}
        } catch (Exception e) {
        	log.info("请检查输入参数!{}{}{}{}"+ "startTime= "+ startTime + "endTime= "+endTime + "type= "+type + "list= "+ list.toString());
            e.printStackTrace();
        }
        return cars; 
    }

    private void refine(List<CarInfo> cars,CarInfo info, String type,JSONObject map, Long id, String name) {
        info.setType((String)map.get("brand_id"));
        info.setLicenseNumber((String) map.get("license_plate1"));
        info.setDate((String) map.get("capture_time"));
        info.setTravelDirection("");
        info.setImgUrl((String) map.get("image_url1"));
        info.setId(id); //卡口id
        info.setName(name); //卡口名称
        cars.add(info);
    }

    @SuppressWarnings("unused")
	private Result getTableName(String hBaseTbName, String locIdAndCaptureTime, String startTime, String endTime) throws IOException {
        Table table = null;
        try {
            connection = ConnectionUtils.createConnection();
            assert connection != null;
            table = connection.getTable(TableName.valueOf(hBaseTbName));
//            SingleColumnValueFilter startFilter = new SingleColumnValueFilter(Bytes.toBytes(Constant.HBASE_COLUMN_FAMILY), Bytes.toBytes("capture_time"), CompareOperator.GREATER_OR_EQUAL,
//                    new BinaryComparator(Bytes.toBytes(startTime)));
//            SingleColumnValueFilter endFilter = new SingleColumnValueFilter(Bytes.toBytes(Constant.HBASE_COLUMN_FAMILY), Bytes.toBytes("capture_time"), CompareOperator.LESS_OR_EQUAL,
//                    new BinaryComparator(Bytes.toBytes(endTime)));
//            FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL, startFilter, endFilter);
            Get get = new Get(Bytes.toBytes(locIdAndCaptureTime));
//            get.setFilter(filterList);
            return table.get(get);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } finally {
            table.close();
            connection.close();
        }

    }

    private List<JSONObject> getESAppointInfo(String licenseNumber,String startTime,String endTime, int size) {
    	String desc = "desc";
        HttpEntity entity = new NStringEntity("{\n" +
				" \"query\": {\n" +
				"    \"bool\": {\n" +
				"        \"must\": [\n" +
				"        	{\n" +
				"                \"term\": {\n" +
				"      		\"license_plate1.keyword\": \"" + licenseNumber + "\"\n" +
				"                }\n" +
				"            }\n," +
				"            {\n" +
				"                \"range\": {\n" +
				"                    \"capture_time.keyword\": {\n" +
				"      				 \"gte\": \"" + startTime + "\"\n" + ","+
				"      				 \"lte\": \"" + endTime + "\"\n" +
				"                    }\n" +
				"                }\n" +
				"            }\n" +
				"        ]\n" +
				"    }\n" +
				"}\n," +
                "  \"sort\": {\n" +
                "    \"capture_time.keyword\": {\n" +
                "      		\"order\": \"" + desc + "\"\n" +
                "    	}\n" +
                "   }\n" +
                "}", ContentType.APPLICATION_JSON);
        return searchIndexByCondition(Constant.ES_INDEX_NAME, entity, size);
    }

    private List<JSONObject> getESLocationId(Long locationId,String startTime, String endTime,int size) {
    	String desc = "desc";
        HttpEntity entity = new NStringEntity("{\n" +
        		" \"query\": {\n" +
		        "    \"bool\": {\n" +
		        "        \"must\": [\n" +
		        "        	{\n" +
		        "                \"term\": {\n" +
		        "      		\"location_id\": \"" + locationId + "\"\n" +
		        "                }\n" +
		        "            }\n," +
		        "            {\n" +
		        "                \"range\": {\n" +
		        "                    \"capture_time.keyword\": {\n" +
		        "      				 \"gte\": \"" + startTime + "\"\n" + ","+
		        "      				 \"lte\": \"" + endTime + "\"\n" +
		        "                    }\n" +
		        "                }\n" +
		        "            }\n" +
		        "        ]\n" +
		        "    }\n" +
		        "}\n," +
		        " \"sort\":{\n" +
		    	"  	\"capture_time.keyword\":{\n" +
		    	"      		\"order\": \"" + desc + "\"\n" +
		    	"  	}\n" +
		    	"}\n" +
                "}", ContentType.APPLICATION_JSON);
        return searchIndexByCondition(Constant.ES_INDEX_NAME, entity , size);
    }

    public List<JSONObject> searchIndexByCondition(String endpoint, HttpEntity entity ,int size) {
        List<JSONObject> result = new ArrayList<JSONObject>();
        try {
            connector = ConnectionUtils.createConnector();
            String method = "GET";
            endpoint = endpoint + "/_search"+ "?size=" + size;
            Request request = new Request(method, endpoint);
            request.setEntity(entity);
            Response response = connector.performRequest(request);
            String indicesInfo = EntityUtils.toString(response.getEntity());

            JSONObject jsonObject = JSONObject.parseObject(indicesInfo);
            JSONObject hitsObj = (JSONObject) jsonObject.get("hits");
            JSONArray hitsArr = (JSONArray) hitsObj.get("hits");

            for (Object object : hitsArr) {
                JSONObject json = (JSONObject) object;
                JSONObject source = (JSONObject) json.get("_source");
                result.add(source);
            }
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
        	try {
				connector.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
        }
       
    }

    @SuppressWarnings("unused")
    private List<String> searchLocationId(String endpoint, HttpEntity entity){
        List<String> result = new ArrayList<String>();
        try {
            String method = "GET";
            endpoint = endpoint + "/_search";
            Request request = new Request(method, endpoint);
            request.setEntity(entity);
            Response response = connector.performRequest(request);
            String indicesInfo = EntityUtils.toString(response.getEntity());

            JSONObject jsonObject = JSONObject.parseObject(indicesInfo);
            JSONObject hitsObj = (JSONObject) jsonObject.get("hits");
            JSONArray hitsArr = (JSONArray) hitsObj.get("hits");

            for (Object object : hitsArr) {
                JSONObject json = (JSONObject) object;
                JSONObject source = (JSONObject) json.get("_source");
                String locationIds = (String) source.get("location_id");
                result.add(locationIds);
            }
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
        	 try {
				connector.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
        }
        
    }

    private boolean check(Point2D.Double point, ArrayList<Point2D.Double> pointList) {
        GeneralPath generalPath = new GeneralPath(GeneralPath.WIND_EVEN_ODD,pointList.size());
        Point2D.Double first = pointList.get(0);
        //通过移动到指定坐标(以双精度指定)将一个点添加到路径中
        generalPath.moveTo(first.x, first.y);
        pointList.remove(0);
        for (Point2D.Double d : pointList) {
            generalPath.lineTo(d.x, d.y);
        }
        //将几何多边de进行封闭
        generalPath.lineTo(first.x, first.y);
        generalPath.closePath();
        //判断指定point2D是否在shape的边界内
        return generalPath.contains(point);
    }
}
